home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / msysjour / vol06 / 03 / lanman3 / wndproc.c < prev   
C/C++ Source or Header  |  1991-05-01  |  18KB  |  703 lines

  1. //===================================================================
  2. //  WndProc.c
  3. //===================================================================
  4.  
  5. #include "phone.h"
  6. #include "runtime.h"
  7.  
  8. #define ERROR_PIPE_BROKEN    109
  9. #define ERROR_INVALID_HANDLE    6
  10. #define TIMER_TICK        50
  11.  
  12. static    char szEditClass[]  = "edit";
  13. static    BOOL timerSet = FALSE;
  14. static    BOOL exitFlag = FALSE;
  15.  
  16. FARPROC lpfnLocalChild;     //... pointer to local window subclass
  17. FARPROC LocalProcInst;        //... local procedure instance
  18. FARPROC lpfnConfigDialogProc;    //... pointer to Config subclass
  19. FARPROC lpfnCallDialogProc;    //... pointer to Call subclass
  20. FARPROC lpfnAboutDialogProc;    //... pointer to About subclass
  21.  
  22. char    format[80];        //... used for wsprintf()
  23. BOOL    config = FALSE;     //... indicates proper configuration
  24. STATE    state = START_STATE;    //... state variable
  25. HWND    hLocalChild;        //... handle to local window
  26. HWND    hRemoteChild;        //... handle to remote window
  27. int    PipeHandle = -1;    //... this is the handle of THE pipe.
  28.  
  29. //...    Name buffers
  30.  
  31. char    szClientName[NAMESIZE] = "";
  32. char    szRemoteName[NAMESIZE] = "";
  33. char    szPbxName[NAMESIZE];
  34. char    szPipeName[RMLEN+1];
  35.  
  36. WORD    ConnectToPbx(void);
  37.  
  38. long FAR PASCAL WndProc(hWnd, iMessage, wParam, lParam)
  39. HWND     hWnd;
  40. unsigned iMessage;
  41. WORD     wParam;
  42. LONG     lParam;
  43. {
  44.     short        Row, Center;
  45.     static        short Width, Height;
  46.     WORD        nBytes;
  47.     WORD        rc;
  48.     HDC         hDC;
  49.     PAINTSTRUCT     ps;
  50.     TEXTMETRIC        tm;
  51.     RECT        rect;
  52.     static HWND     hInstance;
  53.  
  54.     switch(iMessage)
  55.     {
  56.     case WM_CREATE:
  57.         //=======================================================
  58.         //    Set up Local Edit Control
  59.         //=======================================================
  60.  
  61.         hInstance = ((LPCREATESTRUCT) lParam)->hInstance;
  62.  
  63.         hLocalChild = CreateWindow(szEditClass,
  64.                        NULL, EDITSTYLE,
  65.                        0, 0, 0, 0,
  66.                        hWnd, LOCAL_ID,
  67.                        hInstance, NULL);
  68.  
  69.         lpfnLocalChild = (FARPROC) GetWindowLong(hLocalChild,
  70.                              GWL_WNDPROC);
  71.  
  72.         LocalProcInst = MakeProcInstance(
  73.                 (FARPROC) LocalProc,
  74.                 GetWindowWord(hWnd, GWW_HINSTANCE));
  75.  
  76.         SetWindowLong(hLocalChild,
  77.               GWL_WNDPROC,
  78.               (LONG) LocalProcInst);
  79.  
  80.         //=======================================================
  81.         //    Set up Remote Edit Control
  82.         //=======================================================
  83.  
  84.         hRemoteChild = CreateWindow(szEditClass,
  85.                 NULL, EDITSTYLE,
  86.                 0, 0, 0, 0, hWnd,
  87.                 REMOTE_ID,
  88.                 hInstance,
  89.                 NULL);
  90.  
  91.         //=======================================================
  92.         //    Set Dialog procedure pointers
  93.         //=======================================================
  94.  
  95.         lpfnConfigDialogProc = MakeProcInstance(ConfigDialogProc,
  96.                         hInstance);
  97.  
  98.         lpfnCallDialogProc = MakeProcInstance(CallDialogProc,
  99.                             hInstance);
  100.  
  101.         lpfnAboutDialogProc = MakeProcInstance(AboutDialogProc,
  102.                             hInstance);
  103.  
  104.         if ( PbxSearch(szPbxName) == NERR_Success )
  105.         {
  106.         strcpy(szPipeName, szPbxName);
  107.         strcat(szPipeName, PIPELINE);
  108.  
  109.         state = IDLE_STATE;
  110.         }
  111.         else
  112.         {
  113.         PostMessage(hWnd, WM_DESTROY, 0, 0L);
  114.         }
  115.         break;
  116.  
  117.     case WM_SETFOCUS:
  118.         SetFocus(hLocalChild);
  119.         break;
  120.  
  121.     case WM_PAINT:
  122.         hDC = BeginPaint(hWnd, &ps);
  123.         SetBkColor(hDC, RGB(0, 0, 255));
  124.         GetTextMetrics(hDC, &tm);
  125.  
  126.         SetTextColor(hDC, RGB(255, 255, 255));
  127.  
  128.         Row = tm.tmHeight + tm.tmExternalLeading;
  129.  
  130.         rect.top    = 0;
  131.         rect.left    = 0;
  132.         rect.right    = Width;
  133.         rect.bottom = Row;
  134.  
  135.         Center = (Width - 5 * tm.tmAveCharWidth) / 2;
  136.         ExtTextOut(hDC, Center, 0,
  137.                ETO_OPAQUE, &rect,
  138.                "LOCAL", 5, NULL);
  139.  
  140.         rect.left    = 0;
  141.         rect.top    = Height;
  142.         rect.right    = Width;
  143.         rect.bottom = Height+Row;
  144.  
  145.         Center = (Width - 6 * tm.tmAveCharWidth) / 2;
  146.  
  147.         ExtTextOut(hDC, Center, Height,
  148.                ETO_OPAQUE, &rect,
  149.                "REMOTE", 6, NULL);
  150.  
  151.         EndPaint(hWnd, &ps);
  152.         break;
  153.  
  154.     case WM_SIZE:
  155.         Width  = LOWORD(lParam);
  156.         Height = HIWORD(lParam) >> 1;
  157.  
  158.         hDC = BeginPaint(hWnd, &ps);
  159.  
  160.         GetTextMetrics(hDC, &tm);
  161.         Row = tm.tmHeight + tm.tmExternalLeading;
  162.  
  163.         MoveWindow(hLocalChild, 0, Row, Width,
  164.                Height-Row, TRUE);
  165.  
  166.         MoveWindow(hRemoteChild, 0, Row+Height,
  167.                Width, Height-Row, TRUE);
  168.  
  169.         EndPaint(hWnd, &ps);
  170.  
  171.         InvalidateRect(hWnd, NULL, TRUE);
  172.         break;
  173.  
  174.     //===========================================================
  175.     //  The following cases apply to menu options. (e.g. CALL)
  176.     //===========================================================
  177.  
  178.     case WM_COMMAND:
  179.         switch(wParam)
  180.         {
  181.         case IDM_CALL:
  182.             if ( !config )
  183.             {
  184.             DisplayMsgBox(hParent,
  185.                       "You are not configured!");
  186.             }
  187.             else
  188.             {
  189.             if ( state == IDLE_STATE )
  190.             {
  191.                 if ( DialogBox(hInstance,
  192.                        "CallBox",
  193.                        hWnd,
  194.                        lpfnCallDialogProc) )
  195.                 {
  196.                 InvalidateRect(hWnd, NULL, TRUE);
  197.                 }
  198.             }
  199.             else
  200.             {
  201.                 DisplayMsgBox(hWnd,
  202.                 "You must hangup before making call.");
  203.             }
  204.             }
  205.             break;
  206.  
  207.         case IDM_CONFIG:
  208.             if ( DialogBox(hInstance,
  209.                    "ConfigBox",
  210.                    hWnd,
  211.                    lpfnConfigDialogProc) )
  212.              {
  213.             InvalidateRect(hWnd, NULL, TRUE);
  214.              }
  215.  
  216.             if ( !config && strlen(szClientName) )
  217.             {
  218.             config = TRUE;
  219.             ConnectToPbx();
  220.             }
  221.             break;
  222.  
  223.         case IDM_HANGUP:
  224.             if ( state == TALK_STATE )
  225.             {
  226.             HANGUP hangup;
  227.  
  228.             hangup.wPktId = HANGUP_ID;
  229.             hangup.wPktSize = sizeof(HANGUP);
  230.             hangup.wRetCode = 0;
  231.  
  232.             _lwrite(PipeHandle,
  233.                 (LPSTR) &hangup,
  234.                 sizeof(HANGUP));
  235.  
  236.             ClearEditWindow(hLocalChild);
  237.             ClearEditWindow(hRemoteChild);
  238.  
  239.             state = HANGUP_STATE;
  240.             }
  241.             else
  242.             {
  243.                DisplayMsgBox(hWnd, "You are not connected!");
  244.             }
  245.             break;
  246.  
  247.         case IDM_EXIT:
  248.             exitFlag = TRUE;
  249.             SendMessage(hWnd, WM_COMMAND, IDM_HANGUP, 0L);
  250.             break;
  251.  
  252.         case IDM_ABOUT:
  253.             DialogBox(hInstance,
  254.                   "AboutBox",
  255.                   hWnd,
  256.                   lpfnAboutDialogProc);
  257.             break;
  258.  
  259.         default:
  260.             break;
  261.         }
  262.         break;
  263.  
  264.     //===========================================================
  265.     //  All incoming data from PBX is read here. Since data can
  266.     //  arrive asynchronously from PBX or the other client and
  267.     //  since there is no facility for notifying this application
  268.     //  of available data, we read the pipe on discrete time
  269.     //  intervals. For each timer message we peek the pipe to
  270.     //  see if data is available. If there data exists, we
  271.     //  switch to the appropriate case label and satisfy the
  272.     //  next request a in first come first serve order.
  273.     //===========================================================
  274.  
  275.     case WM_TIMER:
  276.         //=======================================================
  277.         // At any time we may receive a hangup request and we
  278.         // must handle it immediately.
  279.         //=======================================================
  280.  
  281.         if ( state == HANGUP_STATE )
  282.         {
  283.         WORD fState, err;
  284.  
  285.         //... check if the handle is valid
  286.  
  287.         err = DosQNmPHandState(PipeHandle, &fState);
  288.  
  289.         //... if so, the pipe is disconnected
  290.         if ( err == ERROR_PIPE_BROKEN ||
  291.              err == ERROR_INVALID_HANDLE )
  292.         {
  293.             state = IDLE_STATE;     //... enter idle state
  294.  
  295.             if ( timerSet )        //... turn off the timer
  296.             {
  297.             KillTimer(hWnd, 1);
  298.             timerSet = FALSE;
  299.             }
  300.  
  301.             //... If the exit flag is set then the hangup
  302.             //... was sent as a result of a user exit so
  303.             //... we must post a quit message and exit the
  304.             //... program. Otherwise, we just hungup so we
  305.             //... need ro re-connect to the PBX.
  306.  
  307.             if ( exitFlag )
  308.             PostMessage(hWnd, WM_DESTROY, 0, 0L);
  309.             else
  310.             ConnectToPbx();
  311.         }
  312.         }
  313.         else
  314.         {
  315.         //===================================================
  316.         //  The incoming data can take a variety of forms
  317.         //  so we use a union to save space while at the
  318.         //  same time you can use convient struct notation
  319.         //  instead of fancy casting.
  320.         //===================================================
  321.  
  322.         union {
  323.             HEADER  header;    //... header message
  324.             PBXPKT  pbx;    //... pbx message
  325.             CHRMSG  chrmsg;    //... char message
  326.             HANGUP  hangup;    //... hangup message
  327.         } packet;
  328.         WORD nBytesRead, nBytesAvail, err;
  329.  
  330.         //===================================================
  331.         //  PBX uses a byte-mode pipe and its own message
  332.         //  headers. Each message retrieved (including
  333.         //  phone specific) has the same header with an
  334.         //  opcode identifying the type of message. Since
  335.         //  we do not know how many bytes there are to read
  336.         //  and we must read them all, we shall do a peek
  337.         //  on the pipe. The number of bytes we will peek
  338.         //  is the size of the common header.
  339.         //===================================================
  340.  
  341.         err = PeekPipe(PipeHandle, &packet, sizeof(HEADER),
  342.                   &nBytesRead, &nBytesAvail);
  343.  
  344.         if ( err || nBytesAvail == 0 )
  345.         {
  346.             break;  //... failure peeking pipe or no data
  347.         }
  348.  
  349.         //===================================================
  350.         //  At this point, we must switch on the message
  351.         //  type, disregarding the ACK bit. The independent
  352.         //  messages will take care of the ACK if one is
  353.         //  received.
  354.         //===================================================
  355.  
  356.         switch( (int) (packet.header.wPktId & ~ACK) )
  357.         {
  358.             case LISTQUERY:
  359.             //===============================================
  360.             //    Obtain the list of users at the PBX.
  361.             //===============================================
  362.             if (state != START_STATE )
  363.             {
  364.                 ReadListQuery();
  365.             }
  366.             break;
  367.  
  368.             case REGISTER:
  369.             //===============================================
  370.             //    PBX will send back ACK for each register
  371.             //    sent to it. The ACK will contain a return
  372.             //    code which is not checked here inorder to
  373.             //    keep this code simple, but should be.
  374.             //===============================================
  375.             if ( (packet.header.wPktId & ACK) == ACK )
  376.             {
  377.                 _lread(PipeHandle,
  378.                    (LPSTR) &packet,
  379.                    sizeof(PBXPKT));
  380.             }
  381.             break;
  382.  
  383.             case CHRMSG_ID:
  384.             //===============================================
  385.             //    Once we are connected to another client,
  386.             //    the dialog will consist of messages containing
  387.             //    each character typed. The message is read
  388.             //    and sent to the remote child window using
  389.             //    the PostMessage() function.
  390.             //===============================================
  391.             if ( state == TALK_STATE )
  392.             {
  393.                 do {
  394.                 _lread(PipeHandle,
  395.                        (LPSTR) &packet,
  396.                        sizeof(CHRMSG));
  397.  
  398.                 SendMessage(hRemoteChild,
  399.                         WM_CHAR,
  400.                         packet.chrmsg.wParam,
  401.                         packet.chrmsg.lParam);
  402.  
  403.                 err = PeekPipe(PipeHandle,
  404.                            &packet,
  405.                            sizeof(HEADER),
  406.                            &nBytesRead,
  407.                            &nBytesAvail);
  408.  
  409.                 if (err || nBytesRead == 0)
  410.                 {
  411.                     break;
  412.                 }
  413.                 }
  414.                 while(packet.header.wPktId==CHRMSG_ID);
  415.             }
  416.             break;
  417.  
  418.             case HANGUP_ID:
  419.             //===========================================
  420.             //  During a dialog either client can hangup.
  421.             //  When a client hangups up, a hangup
  422.             //  message is sent to the remote client and
  423.             //  is processed here. PBX does not notify
  424.             //  the remote client that its pipe is being
  425.             //  closed, therefore, the remote client will
  426.             //  not know until its next pipe operation
  427.             //  fails; this is most undesirable. This
  428.             //  hangup message is just a nice way of
  429.             //  telling the client to disconnect.
  430.             //===========================================
  431.             if ( (packet.header.wPktId & ACK) == 0 )
  432.             {
  433.                 state = HANGUP_STATE;
  434.  
  435.                 _lread(PipeHandle,
  436.                    (LPSTR) &packet,
  437.                    sizeof(HANGUP));
  438.  
  439.                 _lclose(PipeHandle);
  440.  
  441.                 ClearEditWindow(hLocalChild);
  442.                 ClearEditWindow(hRemoteChild);
  443.  
  444.                 strcpy(format, szRemoteName);
  445.                 strcat(format, " HAS HUNGUP");
  446.                 DisplayMsgBox(hWnd, format);
  447.             }
  448.             break;
  449.  
  450.             case CONNECT:
  451.             //==========================================
  452.             // The most complex message to process is
  453.             // the CONNECT message. The following
  454.             // sequence illustrates the handshacking
  455.             // sequence.
  456.             //
  457.             //    CALLER             CALLEE
  458.             //    ______             ------
  459.             //  Send Connect to PBX   Recv connect
  460.             //  Recv ACK from PBX      Send ACK to caller
  461.             //  Recv ACK from callee
  462.             //==========================================
  463.             if ( (packet.header.wPktId & ACK) == ACK )
  464.             {
  465.                 switch(state)
  466.                 {
  467.                 case CALL_STATE:
  468.                 //==================================
  469.                 //  Receive ACK from PBX here and
  470.                 //  wait state, waiting for callee
  471.                 //  ACK.
  472.                 //==================================
  473.                     err = _lread(PipeHandle,
  474.                          (LPSTR) &packet,
  475.                          sizeof(PBXPKT));
  476.  
  477.                     state = ( (int) err > 0 ?
  478.                           WAIT_STATE :
  479.                           IDLE_STATE );
  480.                     break;
  481.  
  482.                 case WAIT_STATE:
  483.                 //==================================
  484.                 //  Receive ACK from callee and
  485.                 //  enter the talk state.
  486.                 //==================================
  487.                     _lread(PipeHandle,
  488.                       (LPSTR) &packet,
  489.                       sizeof(PBXPKT));
  490.  
  491.                     if ( packet.pbx.usRetCode )
  492.                     {
  493.                     state = HANGUP_STATE;
  494.  
  495.                     _lclose(PipeHandle);
  496.  
  497.                     DisplayMsgBox(hWnd,
  498.                           "CALL REFUSED!");
  499.                     }
  500.                     else
  501.                     {
  502.                     state = TALK_STATE;
  503.  
  504.                     DisplayMsgBox(hWnd,
  505.                            "YOU MAY TYPE");
  506.                     }
  507.                     break;
  508.  
  509.                 default: break;
  510.                 }
  511.             }
  512.             else
  513.             {
  514.                 //======================================
  515.                 //    Receive CONNECT from PBX signaling
  516.                 //    that we are being called. To keep
  517.                 //    this sample program simple, the
  518.                 //    callee does not get the option to
  519.                 //    to refuse the call.
  520.                 //======================================
  521.                 if ( state == IDLE_STATE )
  522.                 {
  523.                 _lread(PipeHandle,
  524.                        (LPSTR) &packet,
  525.                        sizeof(PBXPKT));
  526.  
  527.                 strcpy(szRemoteName,
  528.                       packet.pbx.aPBXName[0].pszName);
  529.  
  530.                 strcpy(format, szRemoteName);
  531.                 strcat(format, " IS CALLING YOU");
  532.  
  533.                 rc = MessageBox(hWnd,
  534.                        format,
  535.                        PROGNAME,
  536.                        MB_ICONEXCLAMATION|MB_YESNO);
  537.  
  538.                 packet.pbx.usPktID = (CONNECT | ACK);
  539.                 packet.pbx.usPktSize = sizeof(PBXPKT);
  540.  
  541.                 if ( rc == IDYES )
  542.                 {
  543.                     state = TALK_STATE;
  544.                     packet.pbx.usRetCode = 0;
  545.                 }
  546.                 else
  547.                 {
  548.                     state = HANGUP_STATE;
  549.                     packet.pbx.usRetCode = -1;
  550.                 }
  551.  
  552.                 _lwrite(PipeHandle,
  553.                     (LPSTR) &packet,
  554.                     sizeof(PBXPKT));
  555.                 }
  556.             }
  557.             break;
  558.         }
  559.         }
  560.         break;
  561.  
  562.     case WM_DESTROY:
  563.         if ( state == START_STATE )
  564.         {
  565.         DisplayMsgBox(hWnd,
  566.         "Initialization failed. Program will terminate.");
  567.         }
  568.         else if ( state != TALK_STATE )
  569.         {
  570.         _lclose(PipeHandle);
  571.         }
  572.  
  573.         FreeProcInstance(lpfnConfigDialogProc);
  574.         FreeProcInstance(lpfnCallDialogProc);
  575.         FreeProcInstance(lpfnAboutDialogProc);
  576.         PostQuitMessage(0);     // quit program
  577.         break;
  578.  
  579.     default:
  580.         return DefWindowProc(hWnd, iMessage, wParam, lParam);
  581.     }
  582.  
  583.     return 0L;
  584. }
  585.  
  586. //===================================================================
  587. //  ConnectToPbx()
  588. //
  589. //  This procedure performs the OpenPipe, PbxRegister, start timer
  590. //  and SubmitListQuery sequence.
  591. //
  592. //===================================================================
  593.  
  594. WORD ConnectToPbx(void)
  595. {
  596.     WORD err;
  597.  
  598.     err = OpenPipe(&PipeHandle, szPipeName);
  599.  
  600.     if ( err )
  601.     {
  602.     wsprintf(format,
  603.          "Error opening pipe: %u", err);
  604.  
  605.     DisplayMsgBox(hParent, format);
  606.     }
  607.     else
  608.     {
  609.     err = PbxRegister(PipeHandle, szClientName, PHONE_ID);
  610.  
  611.     if ( err )
  612.     {
  613.         wsprintf(format, "PBX Register error %u", err);
  614.         DisplayMsgBox(hParent, format);
  615.     }
  616.     else
  617.     {
  618.         if ( !timerSet )
  619.         {
  620.         SetTimer(hParent, 1, TIMER_TICK, NULL);
  621.         timerSet = TRUE;
  622.         }
  623.  
  624.         if ( SubmitListQuery() )
  625.         {
  626.         DisplayMsgBox(hParent, "SubmitListQuery failed");
  627.         }
  628.     }
  629.     }
  630.  
  631.     return err;
  632. }
  633.  
  634. //===================================================================
  635. //  LocalProc -- Controls local window
  636. //
  637. //  This procesdure it the entry point for all messages being sent
  638. //  to the LOCAL window.
  639. //===================================================================
  640.  
  641. long FAR PASCAL LocalProc(hWnd, iMessage, wParam, lParam)
  642. HWND      hWnd;
  643. unsigned  iMessage;
  644. WORD      wParam;
  645. LONG      lParam;
  646. {
  647.     int   nBytes, rc;
  648.     WORD  chr;
  649.  
  650.     if ( iMessage != WM_CHAR )
  651.     {
  652.     return CallWindowProc(lpfnLocalChild, hWnd,
  653.                   iMessage, wParam, lParam);
  654.     }
  655.  
  656.     if ( state != TALK_STATE )
  657.     {
  658.     if ( iMessage == WM_KEYDOWN )
  659.     {
  660.         DisplayMsgBox(hParent,
  661.               "Not currently connected!");
  662.     }
  663.  
  664.     return CallWindowProc(lpfnLocalChild, hWnd,
  665.                   WM_CLEAR, wParam, lParam);
  666.     }
  667.     else
  668.     {
  669.     CHRMSG chrmsg;
  670.  
  671.     chrmsg.header.wPktId = CHRMSG_ID;
  672.     chrmsg.header.wPktSize = sizeof(CHRMSG);
  673.     chrmsg.wParam = wParam;
  674.     chrmsg.lParam = lParam;
  675.  
  676.     _lwrite(PipeHandle, (LPSTR) &chrmsg, sizeof(CHRMSG));
  677.     }
  678.  
  679.     return CallWindowProc(lpfnLocalChild, hWnd,
  680.               iMessage, wParam, lParam);
  681. }
  682.  
  683. //===================================================================
  684. //  ClearEditWindow() clears the child windows after
  685. //  a conversation has terminated.
  686. //===================================================================
  687.  
  688. void FAR PASCAL ClearEditWindow(hWnd)
  689. HWND hWnd;
  690. {
  691.     SendMessage(hWnd, EM_SETSEL, 0, MAKELONG(0, 32767));
  692.     SendMessage(hWnd, EM_REPLACESEL, 0, (LONG) (LPVOID) "");
  693. }
  694.  
  695. //===================================================================
  696. //  DisplayMsgBox() is used for alerting the user.
  697. //===================================================================
  698.  
  699. void FAR PASCAL DisplayMsgBox(HWND hWnd, char *str)
  700. {
  701.     MessageBox(hWnd, str, PROGNAME, MB_ICONEXCLAMATION | MB_OK);
  702. }
  703.